package lib.bone.admin.controller.research;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.Validator;
import com.alibaba.excel.EasyExcel;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lib.bone.access.config.cycle.NepuCycle;
import lib.bone.access.module.dict.entity.NepuSubjectDict;
import lib.bone.admin.anno.FormLock;
import lib.bone.access.constant.ResearchTypeConst;
import lib.bone.access.constant.SubjectTypeConst;
import lib.bone.admin.controller.system.dto.SubjectImportDTO;
import lib.bone.admin.controller.system.dto.TopicImportDTO;
import lib.bone.admin.controller.system.listener.SubjectListener;
import lib.bone.admin.controller.system.listener.TopicListener;
import lib.bone.audit.workload.service.NepuWorkloadService;
import lib.bone.nepudata.domain.dto.subject.NepuSubjectAddDTO;
import lib.bone.nepudata.domain.dto.subject.NepuSubjectQueryDTO;
import lib.bone.nepudata.domain.dto.subject.NepuSubjectUpdateDTO;
import lib.bone.ext.draft.NepuDraft;
import lib.bone.ext.draft.NepuDraftService;
import lib.bone.access.config.cycle.NepuCycleService;
import lib.bone.access.module.dict.DictServiceCtl;
import lib.bone.access.module.dict.impl.SubjectDictServiceImpl;
import lib.bone.access.module.oss.NepuResearchFileService;
import lib.bone.nepudata.domain.entity.NepuSubject;
import lib.bone.nepudata.expose.WorkloadService;
import lib.bone.nepudata.service.ResearchServiceCtl;
import lib.bone.nepudata.service.impl.NepuSubjectServiceImpl;
import lib.bone.admin.anno.WebLog;
import lib.bone.admin.constant.MethodTypeConst;
import lib.bone.admin.domain.dto.FileUpdateDTO;
import lib.bone.common.constant.ResponseCodeConst;
import lib.bone.common.core.domain.ResponseDTO;
import lib.bone.common.core.redis.RedisCache;
import lib.bone.common.utils.JsonUtil;
import lib.bone.flow.domain.dto.FlowParam;
import lib.bone.flow.service.FlowWorkCtl;
import lib.bone.system.module.iojob.domain.IOJob;
import lib.bone.system.module.iojob.service.IOJobService;
import lib.bone.system.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;

/**
 * @Author : cg
 * @Date : 2022-1-13
 * 未完成
 */

/**
 * @author: kindear
 */
@Slf4j
@RestController
@RequestMapping("nepu")
@Api(tags = "横向课题")
public class NepuSubjectController {

    @Value("${file-upload-service.path}")
    private String fileParentPath;


    @Autowired
    NepuDraftService draftService;

    @Autowired
    ResearchServiceCtl researchServiceCtl;

    @Autowired
    DictServiceCtl dictServiceCtl;

    @Autowired
    RedisCache redisCache;

    @Autowired
    NepuSubjectServiceImpl nepuSubjectService;

    @Autowired
    NepuResearchFileService nepuResearchFileService;

    @Autowired
    FlowWorkCtl flowWorkCtl;

    @Autowired
    NepuCycleService cycleService;

    @Autowired
    SubjectDictServiceImpl dictService;

    @Autowired
    IOJobService ioJobService;

    @Autowired
    SysUserService sysUserService;

    @Autowired
    NepuWorkloadService nepuWorkloadService;

    /**
     * 表单校验
     * @param dto
     * @return
     */
    public String formValid(NepuSubjectAddDTO dto){
        // 表单重复性校验
        String errMsg = "";
//        Optional<NepuSubject> awardOp = nepuSubjectService.findBySubjectNameAndLeader(
//                dto.getSubjectName(),
//                dto.getLeader()
//        );
//        if (awardOp.isPresent()) {
//            errMsg = "存在重复记录";
//            return errMsg;
//        }
        Long operator = StpUtil.getLoginIdAsLong();
        Long leaderId = dto.getLeaderId();
        if (!leaderId.equals(operator)){
            errMsg = "您不是负责人，无法申报该项目";
            return errMsg;
        }
        List<Long> userIds = dto.getUserIdList();
        if (userIds.contains(dto.getLeaderId())){
            errMsg = "参与人员中不需添加负责人";
            return errMsg;
        }
        return errMsg;
    }

    @PostMapping("subject/import")
    @ApiOperation(value = "横向课题导入")
    public ResponseDTO subjectImport(MultipartFile file, @RequestParam("cycleId") String cycleId) throws IOException {
        Optional<NepuCycle> cycleOp = cycleService.getById(cycleId);
        // 新建导入任务
        IOJob ioJob = ioJobService.createImportJob();
        if (!cycleOp.isPresent()) return ResponseDTO.wrap(ResponseCodeConst.NOT_FOUND);
        NepuCycle nepuCycle = cycleOp.get();
        String parentCycleId = nepuCycle.getParentId();
        EasyExcel.read(file.getInputStream(), SubjectImportDTO.class, new SubjectListener(sysUserService,ioJobService,nepuSubjectService,cycleId,parentCycleId, ioJob.getId(), fileParentPath,dictService,nepuCycle,nepuWorkloadService)).sheet(0).doRead();
        return ResponseDTO.succMsg("写入成功");
    }

    @PostMapping("subjects/storage")
    @FormLock(lockKey = "SUBJECT_STORE",needLogin = true)
    @ApiOperation(value = "暂存记录",notes = "")
    public ResponseDTO<Object> setStorage(@RequestBody  NepuSubjectAddDTO dto){
        Long userId = StpUtil.getLoginIdAsLong();
        NepuDraft draft = new NepuDraft();
        draft.setFormId(ResearchTypeConst.SUBJECT);
        draft.setStatus(1);
        draft.setUserId(userId);
        draft.setFormJsonStr(JsonUtil.obj2String(dto));
        return ResponseDTO.succData(draftService.saveOne(draft));
    }

    @GetMapping("subjects/storage")
    @ApiOperation(value = "获取最新暂存")
    public ResponseDTO<Object> getStorage(){
        Long userId = StpUtil.getLoginIdAsLong();
        Optional<NepuDraft> draftOp = draftService.getLastDraft(userId,ResearchTypeConst.SUBJECT);
        if (!draftOp.isPresent()) return ResponseDTO.wrap(ResponseCodeConst.NOT_FOUND);
        NepuDraft draft = draftOp.get();
        return ResponseDTO.succData(JsonUtil.string2Obj(draft.getFormJsonStr(),NepuSubjectAddDTO.class));
    }

    @GetMapping("subjects/storage/all")
    @ApiOperation(value = "获取全部暂存")
    public ResponseDTO<Object> getAllStorage(){
        Long userId = StpUtil.getLoginIdAsLong();
        List<NepuDraft> drafts = draftService.getFormAllDrafts(userId,ResearchTypeConst.SUBJECT);
        return ResponseDTO.succData(drafts);
    }



    @GetMapping(value = "subjects")
    @ApiOperation(value = "查询全部",notes = "")
    public ResponseDTO<Object> getAll(NepuSubjectQueryDTO nepuSubjectQueryDTO){
        Sort sort;
        if(nepuSubjectQueryDTO.getOrder().equalsIgnoreCase("DESC")){
            sort = Sort.by(Sort.Direction.DESC, nepuSubjectQueryDTO.getSortBy());
        }else {
            sort = Sort.by(Sort.Direction.ASC, nepuSubjectQueryDTO.getSortBy());
        }
        // tips : 页码对应 - 1
        Pageable pageable = PageRequest.of(nepuSubjectQueryDTO.getPageNum() - 1 , nepuSubjectQueryDTO.getPageSize(), sort);

       NepuSubject nepuSubject = new NepuSubject();
        BeanUtil.copyProperties(nepuSubjectQueryDTO,nepuSubject, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
        Example<NepuSubject> example = Example.of(nepuSubject);
        return ResponseDTO.succData(nepuSubjectService.getAll(pageable,example));
        // return nepuSubjectService.getAll(pageable,example);
    }

    @WebLog(module = "nepu-access")
    @PostMapping(value = "subjects")
    @FormLock(lockKey = "SUBJECT_FORM",needLogin = true)
    @ApiOperation(value = "新建记录",notes = "")
    public ResponseDTO<Object> saveOne(@RequestBody @Validated NepuSubjectAddDTO nepuSubjectAddDTO){
        // 1. 获取当前登录用户ID -- 自动拦截未登录用户
        String operator = StpUtil.getLoginIdAsString();
        // 2. 表单校验
        String errMsg = formValid(nepuSubjectAddDTO);
        if (!Validator.isEmpty(errMsg)){
            return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM,errMsg);
        }
        String leaderId = nepuSubjectAddDTO.getLeaderId().toString();
        if (!leaderId.equals(operator)){
            return ResponseDTO.wrap(ResponseCodeConst.FORBIDDEN,"您不是负责人，无法申报该项目");
        }
        if (nepuSubjectAddDTO.getUserIdList().contains(nepuSubjectAddDTO.getLeaderId())){
            return ResponseDTO.wrap(ResponseCodeConst.FORBIDDEN,"参与人员不需加入负责人");
        }
        // 2. 获取当前时间所在周期ID -- 自动拦截不在时间段内的提交
        String cycleId = cycleService.getNowResearchCycleId();
        // 3. 获取词典信息 -- 修改为计算形式
        Optional<NepuSubjectDict> subjectdictOp = dictService.calcDict(nepuSubjectAddDTO.getSubjectType(), nepuSubjectAddDTO.getFunds());
        if (!subjectdictOp.isPresent()){
            return ResponseDTO.wrap(ResponseCodeConst.NOT_FOUND,"未找到匹配工作量条件");
        }
        NepuSubjectDict dict = subjectdictOp.get();
        // 4. 写入记录 并赋值最大工作量
        NepuSubject saveEntity = new NepuSubject();
        saveEntity.setCycleId(cycleId);
        saveEntity.setSubjectDictId(dict.getId());
        BeanUtil.copyProperties(nepuSubjectAddDTO,saveEntity, CopyOptions.create().setIgnoreError(true).setIgnoreNullValue(true));
        saveEntity.setFunds(nepuSubjectAddDTO.getFunds());
        // 具体赋分规则
        if(saveEntity.getSubjectType().equals(SubjectTypeConst.NATURAL)){
            if (nepuSubjectAddDTO.getFunds()<500){
                String str = String.format("%.2f",nepuSubjectAddDTO.getFunds());
                saveEntity.setWorkload(Double.valueOf(str));
            }else {
                saveEntity.setWorkload(500.0);
            }
        }else {
            if (nepuSubjectAddDTO.getFunds()<2){
                int i = (int)(nepuSubjectAddDTO.getFunds()/0.2);
                if (nepuSubjectAddDTO.getFunds()>=0.2){
                    double d = nepuSubjectAddDTO.getFunds() % 0.2;
                    if (d > 0){
                        i = i + 1;
                    }
                }else {
                    i = 1;
                }
                saveEntity.setWorkload(Double.valueOf(i));
            }else {
                saveEntity.setWorkload(dict.getWorkloadMax());
            }
//            else {
//                double workload = 0.0;
//                if (nepuSubjectAddDTO.getFunds()>=2&&nepuSubjectAddDTO.getFunds()<=6){
//                    workload = 30.0;
//                }else if (nepuSubjectAddDTO.getFunds()>6&&nepuSubjectAddDTO.getFunds()<=10){
//                    workload = 50.0;
//                }else if (nepuSubjectAddDTO.getFunds()>10&&nepuSubjectAddDTO.getFunds()<=20){
//                    workload = 80.0;
//                }else if (nepuSubjectAddDTO.getFunds()>20&&nepuSubjectAddDTO.getFunds()<=30){
//                    workload = 100.0;
//                }else if (nepuSubjectAddDTO.getFunds()>30){
//                    workload = 200.0;
//                }
//                System.out.println("workload:"+workload);;
//                saveEntity.setWorkload(workload);
//            }
        }

        NepuSubject subject = (NepuSubject) researchServiceCtl.saveOne(saveEntity);
        // 5. 写入绑定文件信息 -- 修改为异步任务
        List<String> fileIds = nepuSubjectAddDTO.getFileIds();
        nepuResearchFileService.batchBindFile(ResearchTypeConst.SUBJECT,subject.getId(),fileIds);
        // 6. 构建流程参数
        FlowParam flowParam = new FlowParam(ResearchTypeConst.SUBJECT,subject.getId(),subject.getSubjectName(),operator,null);
        System.out.println("flowParam"+flowParam);
//        flowParam.setServiceType(ResearchTypeConst.SUBJECT);
//        flowParam.setServiceId(subject.getId());
//        flowParam.setServiceName(subject.getSubjectName());
//        flowParam.setOperator(operator);
        // 7. 启动流程实例 -- 修改为异步任务
        flowWorkCtl.startProcess("subject-check-01",operator,flowParam);
        return ResponseDTO.succData(subject);
    }

    @WebLog(module = "nepu-access",operate = MethodTypeConst.UPDATE)
    @PutMapping(value = "subjects")
    @ApiOperation(value = "更新单条记录",notes = "")
    public ResponseDTO<Object> updateOne(@RequestBody @Validated NepuSubjectUpdateDTO nepuSubjectUpdateDTO){
        Optional<Object> subjectOp = researchServiceCtl.getById(nepuSubjectUpdateDTO.getId(),ResearchTypeConst.SUBJECT);
        if (!subjectOp.isPresent()){
            return ResponseDTO.wrap(ResponseCodeConst.NOT_FOUND);
        }
        NepuSubject subject = (NepuSubject) subjectOp.get();
        BeanUtil.copyProperties(nepuSubjectUpdateDTO,subject,CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
        return ResponseDTO.succData(researchServiceCtl.updateOne(subject,ResearchTypeConst.SUBJECT));    }

    @GetMapping(value = "subjects/{id}")
    @ApiOperation(value = "查询单条记录",notes = "")
    public ResponseDTO <Object>getOne(@PathVariable("id") String id){
        Optional<Object> entityOp = researchServiceCtl.getById(id,ResearchTypeConst.SUBJECT);
        return entityOp.map(ResponseDTO::succData).orElseGet(() -> ResponseDTO.wrap(ResponseCodeConst.NOT_FOUND));
    }

    @WebLog(module = "nepu-access",operate = MethodTypeConst.DELETE)
    @DeleteMapping(value = "subjects/{id}")
    @ApiOperation(value = "删除单条记录",notes = "")
    public ResponseDTO<Object> deleteOne(@PathVariable("id") String id){
        return researchServiceCtl.deleteById(id,ResearchTypeConst.SUBJECT);
    }

    @WebLog(module = "nepu-access",operate = MethodTypeConst.UPDATE)
    @PutMapping("subjects/files")
    @ApiOperation(value = "更新附件信息",notes = "")
    public ResponseDTO<Object> updateFiles(@RequestBody @Validated FileUpdateDTO dto){
        Long userId = StpUtil.getLoginIdAsLong();
        Optional<Object> subjectOp = researchServiceCtl.getById(dto.getMapperId(),ResearchTypeConst.SUBJECT);
        if (!subjectOp.isPresent()){
            return ResponseDTO.wrap(ResponseCodeConst.NOT_FOUND);
        }
        NepuSubject subject = (NepuSubject)subjectOp.get();
        if (!userId.equals(subject.getLeaderId())){
            return ResponseDTO.wrap(ResponseCodeConst.FORBIDDEN,"非负责人无法修改");
        }
        // 清理之前的附件信息
        nepuResearchFileService.deleteEntityLink(subject.getId());
        // 写入新的附件信息
        List<String> fileIds = dto.getFileIds();
        nepuResearchFileService.batchBindFile(ResearchTypeConst.SUBJECT,subject.getId(),fileIds);
        // 返回操作信息
        return ResponseDTO.succMsg("更新成功");
    }

    @WebLog(module = "nepu-access",operate = MethodTypeConst.UPDATE)
    @PutMapping("subjects/{id}/workload")
    @ApiOperation(value = "修改记录工作量")
    public ResponseDTO<Object> updateWorkload(@PathVariable("id") String id,@RequestParam("workload") Double workload){
        Optional<Object> entityOp = researchServiceCtl.getById(id,ResearchTypeConst.SUBJECT);
        if (!entityOp.isPresent()){
            return ResponseDTO.wrap(ResponseCodeConst.NOT_FOUND,"未找到对应课题记录");
        }
        NepuSubject subject = (NepuSubject)entityOp.get();
        String dictId = subject.getSubjectDictId();
        Optional<Object> dictOp = dictServiceCtl.getById(dictId,ResearchTypeConst.SUBJECT);
        if (!dictOp.isPresent()){
            return ResponseDTO.wrap(ResponseCodeConst.NOT_FOUND,"未找到课题关联词典记录");
        }
        NepuSubjectDict dict = (NepuSubjectDict) dictOp.get();
        if (workload > dict.getWorkloadMax() || workload < dict.getWorkloadMin()){
            return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM,"工作量范围错误");
        }
        subject.setWorkload(workload);
        // 写入记录
        return ResponseDTO.succData(researchServiceCtl.updateOne(subject,ResearchTypeConst.SUBJECT));
    }
}
